package com.googlecode.lazyrecords.lucene;

import org.apache.lucene.search.*;

public class LuceneQueryVisitor {

    private final LuceneQueryPreprocessor preprocessor;

    public LuceneQueryVisitor(LuceneQueryPreprocessor preprocessor) {
        this.preprocessor = preprocessor;
    }

    public Query visit(Query query) {
        if (query instanceof BooleanQuery) {
            return visitBooleanQuery((BooleanQuery) query);
        }
        if (query instanceof ConstantScoreQuery) {
            return visitConstantScoreQuery((ConstantScoreQuery) query);
        }
        if (query instanceof DisjunctionMaxQuery) {
            return visitDisjunctionMaxQuery((DisjunctionMaxQuery) query);
        }
        if (query instanceof TermQuery) {
            return visitTermQuery((TermQuery) query);
        }
        if (query instanceof WildcardQuery) {
            return visitWildcardQuery((WildcardQuery) query);
        }
        if (query instanceof PhraseQuery) {
            return visitPhraseQuery((PhraseQuery) query);
        }
        if (query instanceof PrefixQuery) {
            return visitPrefixQuery((PrefixQuery) query);
        }
        if (query instanceof MultiPhraseQuery) {
            return visitMultiPhraseQuery((MultiPhraseQuery) query);
        }
        if (query instanceof FuzzyQuery) {
            return visitFuzzyQuery((FuzzyQuery) query);
        }
        if (query instanceof RegexpQuery) {
            return visitRegexpQuery((RegexpQuery) query);
        }
        if (query instanceof TermRangeQuery) {
            return visitTermRangeQuery((TermRangeQuery) query);
        }
        if (query instanceof NumericRangeQuery) {
            return visitNumericRangeQuery((NumericRangeQuery) query);
        }
        if (query instanceof MatchAllDocsQuery) {
            return visitMatchAllDocsQuery((MatchAllDocsQuery) query);
        }
        throw new UnsupportedOperationException();
    }

    private Query visitBooleanQuery(BooleanQuery query) {
        BooleanQuery visitedQuery = new BooleanQuery();
        for (BooleanClause clause : query) {
            visitedQuery.add(visit(clause.getQuery()), clause.getOccur());
        }
        return visitedQuery;
    }

    private Query visitConstantScoreQuery(ConstantScoreQuery query) {
        if (query.getQuery() == null) {
            throw new UnsupportedOperationException();
        }
        return new ConstantScoreQuery(visit(query.getQuery()));
    }

    private Query visitDisjunctionMaxQuery(DisjunctionMaxQuery query) {
        final DisjunctionMaxQuery visitedQuery = new DisjunctionMaxQuery(query.getTieBreakerMultiplier());
        for (Query disjunctionQuery : query) {
            visitedQuery.add(visit(disjunctionQuery));
        }
        return visitedQuery;
    }

    private Query visitTermQuery(TermQuery query) {
        return preprocessor.process(query);
    }

    private Query visitWildcardQuery(WildcardQuery query) {
        return preprocessor.process(query);
    }

    private Query visitPhraseQuery(PhraseQuery query) {
        return preprocessor.process(query);
    }

    private Query visitPrefixQuery(PrefixQuery query) {
        return preprocessor.process(query);
    }

    private Query visitMultiPhraseQuery(MultiPhraseQuery query) {
        return preprocessor.process(query);
    }

    private Query visitFuzzyQuery(FuzzyQuery query) {
        return preprocessor.process(query);
    }

    private Query visitRegexpQuery(RegexpQuery query) {
        return preprocessor.process(query);
    }

    private Query visitTermRangeQuery(TermRangeQuery query) {
        return preprocessor.process(query);
    }

    private Query visitNumericRangeQuery(NumericRangeQuery query) {
        return preprocessor.process(query);
    }

    private Query visitMatchAllDocsQuery(MatchAllDocsQuery query) {
        return preprocessor.process(query);
    }

}
